/*	--- ZonedDateTime --- 

LocalDateTime总是表示本地日期和时间，要表示一个带时区的日期和时间，我们就需要ZonedDateTime。

可以简单地把ZonedDateTime理解成LocalDateTime加ZoneId。ZoneId是java.time引入的新的时区类，注意和旧的java.util.TimeZone区别。

要创建一个ZonedDateTime对象，有以下几种方法，一种是通过now()方法返回当前时间：
*/
import java.time.*;

public class Main {
	public static void main(String[] args) {
		ZonedDateTime zbj = ZonedDateTime.now(); // 默认时区
		ZonedDateTime zny = ZonedDateTime.now(ZoneId.of("America/New_York")); // 用指定时区获取当前时间

		System.out.println(zbj);
		System.out.println(zny);
	}
}


// 观察打印的两个ZonedDateTime，发现它们时区不同，但表示的时间都是同一时刻（毫秒数不同是执行语句时的时间差）：
2019-09-15T20:58:18.786182+08:00[Asia/Shanghai]
2019-09-15T08:58:18.788860-04:00[America/New_York]



// 另一种方式是通过给一个LocalDateTime附加一个ZoneId，就可以变成ZonedDateTime：
import java.time.*;

public class Main {
	public static void main(String[] args) {
		LocalDateTime ldt = LocalDateTime.of(2019, 9, 15, 15, 16, 17)l

		ZonedDateTime zbj = ldt.atZone(ZoneId.systemDefault());
		ZonedDateTime zny = ldt.atZone(ZoneId.of("America/New_York"));

		System.out.println(zbj);
		System.out.println(zny);
	}
}


// 以这种方式创建的ZonedDateTime，它的日期和时间与LocalDateTime相同，但附加的时区不同，因此是两个不同的时刻：
2019-09-15T15:16:17+08:00[Asia/Shanghai]
2019-09-15T15:16:17-04:00[America/New_York]



/*
#	时区转换

要转换时区，首先我们需要有一个ZonedDateTime对象，然后，通过withZoneSameInstant()将关联时区转换到另一个时区，转换后日期和时间都会相应调整。

下面的代码演示了如何将北京时间转换为纽约时间：	*/
import java.time.*;

public class Main {
	public static void main(String[] args) {
		// 以中国时区获取当前时间
		ZonedDateTime zbj = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));

		// 转换为纽约时间
		ZonedDateTime zny = ZonedDateTime.now(ZoneId.of("America/New_York"));

		System.out.println(zbj);
		System.out.println(zny);
	}
}



// 要特别注意，时区转换的时候，由于夏令时的存在，不同的日期转换的结果很可能是不同的。这是北京时间9月15日的转换结果：
2019-09-15T21:05:50.187697+08:00[Asia/Shanghai]
2019-09-15T09:05:50.187697-04:00[America/New_York]


// 这是北京时间11月15日的转换结果：
2019-11-15T21:05:50.187697+08:00[Asia/Shanghai]
2019-11-15T08:05:50.187697-05:00[America/New_York]


/*
两次转换后的纽约时间有1小时的夏令时时差。

 涉及到时区时，千万不要自己计算时差，否则难以正确处理夏令时。

------------------------------------------

有了ZonedDateTime，将其转换为本地时间就非常简单： */
ZonedDateTime zdt = ...;
LocalDateTime ldt = zdt.toLocalDateTime();


// 转换为LocalDateTime时，直接丢弃了时区信息。




/* --------------------------------------

#	练习

某航线从'北京'飞到'纽约'需要'13小时20分钟'，请根据【北京起飞日期和时间】计算【到达纽约的当地日期和时间】。	*/
import java.time.*;

public class Main {
    public static void main(String[] args) {
        LocalDateTime departureAtBeijing = LocalDateTime.of(2019, 9, 15, 13, 0, 0);
        int hours = 13; // flight time.HOUR
        int minutes = 20; // flight time.MINUTE

        LocalDateTime arrivalAtNewYork = calculateArrivalAtNY(departureAtBeijing, hours, minutes); // call Function

        System.out.println(departureAtBeijing + " -> " + arrivalAtNewYork);


        // test:
        if (!LocalDateTime.of(2019, 10, 15, 14, 20, 0)
                .equals(calculateArrivalAtNY(LocalDateTime.of(2019, 10, 15, 13, 0, 0), 13, 20))) {
            System.err.println("测试失败!");
        } else if (!LocalDateTime.of(2019, 11, 15, 13, 20, 0)
                .equals(calculateArrivalAtNY(LocalDateTime.of(2019, 11, 15, 13, 0, 0), 13, 20))) {
            System.err.println("测试失败!");
        }

    }


    static LocalDateTime calculateArrivalAtNY(LocalDateTime bj, int h, int m) {

    	// 方法1,一步到位
        return bj.atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneId.of("America/New_York")).plusHours(h).plusMinutes(m).toLocalDateTime();

        // 方法2
        LocalDateTime arrivalBJLocal = bj.plusHours(h).plusMinutes(m);
        ZonedDateTime arrivalBJZone = arrivalBJLocal.atZone(Zone.of("Asia/Shanghai"));
        ZonedDateTime arrivalNYZone = arrivalBJZone.withZoneSameInstant(ZoneId.of("America/New_York"));

        // return arrivalNYZone.toLocalDateTime();

    }
}






/*	---- ZonedDateTime の 小结 ---- 

1.ZonedDateTime是带时区的日期和时间，可用于时区转换；

2.ZonedDateTime和LocalDateTime可以相互转换。

3.LocalDateTime是逻辑时间,比如设定闹钟,计算下一个周二是几号,计算任意两天之间的天数,这些跟时区无关。

而ZonedDateTime是时区时间

你如果仔细看ZonedDateTime源码，它其实是：

	class ZonedDateTime {
	    final LocalDateTime local;
	    final ZoneId zoneId;
	}


是一步一步封装的，而不是一上来就搞个大对象
(Tips: ZonedDateTime仍然提供了plusDays()等加减操作。)


*/
